<?php
/**
 *
 * @author Mr.UBKey
 * @package XPHP
 * @version 0.1 B
 * @copyright XWEB
 */

require_once 'XPHP/String.php';

abstract class XPHP_Controller
{
	/**
	 * Router lưu thông tin về area, controller, action
	 * @var XPHP_Router
	 */
	protected $_router;
	
	/**
	 * Model lưu thông tin về mô hình
	 * @var object
	 * @abstract XPHP_Model
	 */
	protected $model;
	
	/**
	 * View đối tượng lưu trữ dữ liệu chuyển từ controller sang view
	 * @var stdClass
	 */
	public $view;
	
	/**
	 * Tên Layout sử dụng trong trang
	 * @var string Tên Layout
	 */
	protected $layout;
	
	/**
	 * Mảng lưu trữ các tham số truyền vào từ _GET, _POST, REQUEST URI
	 * @var array
	 */
	protected $params = array();
	
	/**
	 * Hỗ trợ mở rộng cho MF_Controller
	 * @var XPHP_Controller_Helper
	 */
	protected $helper;
	
	/**
	 * Hỗ trợ Url
	 */
	protected $url;
	
	/**
	 * Khởi tạo lớp controller
	 * @param XPHP_Router $router
	 */
	public function __construct($router)
	{
		//Gán router cho controller
		$this->_router = $router;
		
		//Khởi tạo view lưu trữ dữ liệu truyền từ controller tới view
		$this->view = new stdClass();
		
		//Lấy toàn bộ các tham số truyền vào dạng POST VÀ GET đưa vào $this->params
		if(isset($_POST))
		{
			foreach ($_POST as $key => $value)
			{
				$this->params[$key] = XPHP_String::secure($value);
			}
		}
		if(isset($_GET))
		{
			foreach ($_GET as $key => $value)
			{
				$this->params[$key] = XPHP_String::secure($value);
			}
		}
		//Lấy toàn bộ các tham số truyền vào dạng GET đưa vào $this->params
		$args = $this->_router->getArgs();
		if(!empty($args))
		{
			for ($i=0; $i<sizeof($args); $i++)
			{
				$this->params[$i] = $args[$i];
			}	
		}
	
		//Khới tạo cho Hỗ trợ Url
		$this->url = new XPHP_Url($router);
			
		//Khởi tạo lớp hỗ trợ cho controller truyền vào router
		require_once 'XPHP/Controller/Helper.php';
		$this->helper = new XPHP_Controller_Helper($this->_router);
		
		//Gọi tới function __init nếu có sau khi khởi tạo lớp
		//Hàm __init() sẽ chạy trước khi chạy mọi action trong controller
		if(method_exists(get_class($this), '_init'))
			$this->_init();
	}
	
	/**
	 * Nếu truyền vào tên tham số phương thức sẽ kiểm tra xem có tồn tại tham số đó không ?
	 * Nếu không truyền vào tham số phương thức sẽ kiểm tra xem có tham số truyền vào hay không ?
	 * @access protected
	 * @param string $param || void
	 * @return boolean
	 */
	protected function hasParams($param = NULL)
	{
		if($param !== NULL)
		{
			if(isset($this->params[$param]))
				return true;
			else 
				return false;
		}
		else 
		{
			if(sizeof($this->params) > 0)
				return true;
			else 
				return false;
		}
	}
	
	/**
	 * Phương thức sẽ gán đối tượng thuộc class MF_Model cho model
	 * @param $object MF_Model
	 * @throws MF_Exception
	 */
	public function setModel($obj)
	{
		if(is_object($obj))
		{
			if(empty($this->model))
				$this->model = $obj;
		}
		else
			throw new XPHP_Exception("Param model is not object");
	}
	
	/**
	 * Kiểm tra xem model có dạng giống tham số truyền vào không
	 * VD: Nếu người dùng POST dữ liệu phương thức sẽ kiểm tra xem có dạng 
	 * giống với model truyền vào không
	 * Nếu kiểm tra thành công gọi phương thức parseModelParams phân tich và gán
	 * các giá trị tương ứng vào $this->model
	 * Trả về true, false
	 * @param $object MF_Model Truyền vào đối tượng thuộc lớp MF_Model để kiểm tra
	 * @throws MF_Exception
	 * @return bool
	 */
	
	protected function hasModel($obj=NULL)
	{
		if($obj === NULL)
		{
			if(empty($this->model))
				throw new XPHP_Exception("Model chưa được định kiểu bạn cần phải truyền vào tham số là đối tượng cho hasModel()");
			else 
				$obj = $this->model;
		}
		if(is_object($obj))
		{	
			if(get_parent_class($obj) != "XPHP_Model")
			{
				throw new XPHP_Exception("Kiểu của model phải được kế thừa từ lớp XPHP_Model");
				return;
			}
			$ref = new XPHP_Reflection($obj);
			$refproperties = $ref->getProperties();
			//Mảng lưu trữ các thuộc tính
			$arrProperties = array();
			foreach ($refproperties as $refproperty)
			{
				$arrProperties[] = $refproperty->getName();
			}
			//Nếu là ajax request
			if($this->isAjaxRequest() && isset($_POST["jsondata"]))
			{
				$arr = json_decode($_POST["jsondata"],true);
				$arrData = array();
				foreach ($arr as $key => $value)
					$arrData[$key] = $value;
				//Kiểm tra các thuộc tính với arrData
				foreach ($arrProperties as $property)
				{
					if(isset($arrData[$property]))
					{
						//Gán đối tượng làm model
						$this->model = $obj;
						//Gọi tới phương thức phân tích để gán giá trị vào model
						$this->parseModelParams();
						//Have property
						return true;
					}
					else
						continue;
				}
			}
			//Nếu người dùng POST dữ liệu
			else 
			{
				//Kiểm tra thuộc tính với các tham số người dùng POST lên
				foreach ($arrProperties as $property)
				{
					if(isset($this->params[$property]))
					{
						//Gán đối tượng làm model
						$this->model = $obj;
						//Gọi tới phương thức phân tích để gán giá trị vào model
						$this->parseModelParams();
						return true;
					}
					else
						continue;
				}
				return false;
			}
		}
		else 
			throw new XPHP_Exception("Phương thức hasModel() tham số truyền vào là một đối tượng kế thừa từ lớp XPHP_Model");
		
	}
	
	/**
	 * Phân tích tham số truyền vào từ POST, GET, AJAX để gán các giá trị tương ứng vào model
	 * @access private
	 * @param XPHP_Model $obj Truyền vào đối tượng thuộc lớp XPHP_Model để kiểm tra
	 * @return boolean
	 */
	
	public function parseModelParams()
	{
		if(is_object($this->model))
		{
			//Lấy ra tên các property của model
			$ref = new XPHP_Reflection($this->model);
			$refproperties = $ref->getProperties();
			//Mảng lưu trữ các thuộc tính
			$propertyNames= array();
			foreach ($refproperties as $refproperty)
			{
				$propertyNames[] = $refproperty->getName();
			}
			//Nếu người dùng sử dụng AJAX request
			if($this->isAjaxRequest() && isset($_POST["jsondata"]))
			{
				$arr = json_decode($_POST["jsondata"],true);
				$arrData = array();
				foreach ($arr as $key => $value)
					$arrData[$key] = $value;
				//Kiểm tra thuộc tính với các tham số người dùng sử dụng ajax gửi lên
				//Gán giá trị tương ứng vào model
				foreach ($propertyNames as $property)
				{
					if(isset($arrData[$property]))
					{
						$this->model->$property = XPHP_String::secure($arrData[$property]);
					}
					else
						continue;
				}
			}
			//Nếu người dùng sử dụng POST
			else 
			{		
				//Kiểm tra thuộc tính với các tham số POST từ client
				//Gán các giá trị tương ứng vào model
				foreach ($propertyNames as $property)
				{
					if(isset($this->params[$property]))
					{
						$this->model->$property = XPHP_String::secure($this->params[$property]);
					}
					else
						continue;
				}
			}
		}
		else 
			return false;
	}
	
	/**
	 * Kiểm tra xem yêu cầu có phải là ajax hay không ?
	 * @param void
	 * @return bool
	 */
	public function isAjaxRequest() 
	{
		return (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && ($_SERVER['HTTP_X_REQUESTED_WITH'] == 'XMLHttpRequest'));
	}
	
	protected function loadLayout($layout)
	{
		$this->layout = $layout;
	}
	
	protected function unloadLayout()
	{
		$this->layout = NULL;
	}
	
	public function getLayout()
	{
		return $this->layout;
	}
	
	public function getModel()
	{
		return $this->model;
	}
	
	/**
	 * Trả về XPHP_View_Result
	 * @param unknown_type $data 
	 */
	protected function view($model=NULL)
	{
		
		require_once 'XPHP/View/Result.php';
		
		if($model !== NULL && get_parent_class($model) == "XPHP_Model")
		{
			$this->setModel($model);
		}		 
		return new XPHP_View_Result();
	}
	
	/**
	 * Overload method RedirectResult.
	 */
	function __call($method_name, $arguments)
	{
    	//we inspect number of arguments
	    if($method_name == "redirect" && count($arguments) == 1)
	    {
	    	return $this->redirect1($arguments[0]);
	    }
	    else if($method_name == "redirect" && count($arguments) == 2 && is_string($arguments[1]))
	    {
	    	return $this->redirect2($arguments[0], $arguments[1]);
	    }
		else if($method_name == "redirect" && count($arguments) == 2 && is_array($arguments[1]))
	    {
	    	return $this->redirect5($arguments[0], $arguments[1]);
	    }
	    else if($method_name == "redirect" && count($arguments) == 3 && is_string($arguments[2]))
	    {
	    	return $this->redirect3($arguments[0], $arguments[1], $arguments[2]);
	    }
		else if($method_name == "redirect" && count($arguments) == 3 && is_array($arguments[2]))
	    {
	    	return $this->redirect6($arguments[0], $arguments[1], $arguments[2]);
	    }
		else if($method_name == "redirect" && count($arguments) == 4)
	    {
	    	return $this->redirect4($arguments[0], $arguments[1], $arguments[2], $arguments[3]);
	    }
	}
	
	public function redirect1($action)
	{
		return new XPHP_View_Result_Redirect($this->url->action($action));
	}
	
	private function redirect2($action, $controller)
	{
		return new XPHP_View_Result_Redirect($this->url->action($action, $controller));
	}
	
	private function redirect3($action, $controller, $area)
	{
		return new XPHP_View_Result_Redirect($this->url->action($action, $controller, $area));
	}
	
	private function redirect4($action, $controller, $area, $args)
	{
		return new XPHP_View_Result_Redirect($this->url->action($action, $controller, $area, $args));
	}
	
	private function redirect5($action, $args)
	{
		return new XPHP_View_Result_Redirect($this->url->action($action, $args));
	}
	
	private function redirect6($action, $controller, $args)
	{
		return new XPHP_View_Result_Redirect($this->url->action($action, $controller, $args));
	}
	
	protected function json($data)
	{
		return new XPHP_View_Result_Json($data);
	}
}